'use strict';

import React, {Component, PropTypes} from 'react';
import {
  StyleSheet,
  View,
  Text,
  Animated,
  Platform,
  Dimensions,
  // Picker as PickerAndroid,
  PickerIOS
} from 'react-native';

import PickerAndroid from './PickerAnd';

let Picker = Platform.OS === 'ios' ? PickerIOS : PickerAndroid;
let PickerItem = Picker.Item;
let {width, height} = Dimensions.get('window');

const longSide = width > height ? width : height;
const shortSide = width > height ? height : width;

export default class PickerAny extends Component {

  static propTypes = {
    style: View.propTypes.style,
    pickerElevation: PropTypes.number,
    pickerBtnText: PropTypes.string,
    pickerCancelBtnText: PropTypes.string,
    pickerBtnStyle: Text.propTypes.style,
    pickerTitle: PropTypes.string,
    pickerTitleStyle: Text.propTypes.style,
    pickerToolBarStyle: View.propTypes.style,
    showMask: PropTypes.bool,
    showDuration: PropTypes.number,
    pickerData: PropTypes.any.isRequired,
    selectedValue: PropTypes.any.isRequired,
    onPickerDone: PropTypes.func,
    onPickerCancel: PropTypes.func,
    onValueChange: PropTypes.func
  };

  static defaultProps = {
    style: {
      width: width
    },
    pickerBtnText: 'Done',
    pickerCancelBtnText: 'Cancel',
    showMask: false,
    showDuration: 300,
    onPickerDone: ()=>{},
    onPickerCancel: ()=>{},
    onValueChange: ()=>{}
  };

  constructor(props, context){
    super(props, context);
  }

  componentWillMount(){
    this.state = this._getStateFromProps(this.props);
  }

  componentWillReceiveProps(newProps){
    let newState = this._getStateFromProps(newProps);
    this.setState(newState);
  }

  shouldComponentUpdate(nextProps, nextState, context){
    return true;
  }

  _getStateFromProps(props){
    //the pickedValue must looks like [wheelone's, wheeltwo's, ...]
    //this.state.selectedValue may be the result of the first pickerWheel
    let {pickerData, selectedValue} = props;
    let pickerStyle = pickerData.constructor === Array ? 'parallel' : 'cascade';
    let firstWheelData;
    let firstPickedData;
    let secondPickedData;
    let secondWheelData;
    let secondPickedDataIndex;
    let thirdWheelData;
    let thirdPickedDataIndex;
    let cascadeData = {};
    let slideAnim = (this.state && this.state.slideAnim ? this.state.slideAnim : new Animated.Value(-height));

    if(pickerStyle === 'parallel'){
      //compatible single wheel sence
      if(selectedValue.constructor !== Array){
        selectedValue = [selectedValue];
      }
      if(pickerData[0].constructor !== Array){
        pickerData = [pickerData];
      }
    }
    else if(pickerStyle === 'cascade'){
      //only support three stage
      firstWheelData = Object.keys(pickerData);
      firstPickedData = props.selectedValue[0];
      secondPickedData = props.selectedValue[1];
      cascadeData = this._getCascadeData(pickerData, selectedValue, firstPickedData, secondPickedData, true);
    }
    //save picked data
    this.pickedValue = JSON.parse(JSON.stringify(selectedValue));
    this.pickerStyle = pickerStyle;
    return {
      ...props,
      pickerData,
      selectedValue,
      //list of first wheel data
      firstWheelData,
      //first wheel selected value
      firstPickedData,
      slideAnim,
      //list of second wheel data and pickedDataIndex
      secondWheelData: cascadeData.secondWheelData,
      secondPickedDataIndex: cascadeData.secondPickedDataIndex,
      //third wheel selected value and pickedDataIndex
      thirdWheelData: cascadeData.thirdWheelData,
      thirdPickedDataIndex: cascadeData.thirdPickedDataIndex
    };
  }

  _slideUp(){
    this._isMoving = true;
    Animated.timing(
      this.state.slideAnim,
      {
        toValue: 0,
        duration: this.state.showDuration,
      }
    ).start((evt) => {
      if(evt.finished) {
        this._isMoving = false;
        this._isPickerShow = true;
      }
    });
  }

  _slideDown(){
    this._isMoving = true;
    Animated.timing(
      this.state.slideAnim,
      {
        toValue: -height,
        duration: this.state.showDuration,
      }
    ).start((evt) => {
      if(evt.finished) {
        this._isMoving = false;
        this._isPickerShow = false;
      }
    });
  }

  _toggle(){
    if(this._isMoving) {
      return;
    }
    if(this._isPickerShow) {
      this._slideDown();
    }
    else{
      this._slideUp();
    }
  }

  toggle(){
    this._toggle();
  }
  show(){
    if(!this._isPickerShow){
      this._slideUp();
    }
  }
  hide(){
    if(this._isPickerShow){
      this._slideDown();
    }
  }
  isPickerShow(){
    return this._isPickerShow;
  }

  _prePressHandle(callback){
    this.pickerWheel.moveUp();
  }

  _nextPressHandle(callback){
    this.pickerWheel.moveDown();
  }

  _pickerCancel(){
    this._toggle();
    this.state.onPickerCancel();
  }

  _pickerFinish(){
    this._toggle();
    this.state.onPickerDone(this.pickedValue);
  }

  _renderParallelWheel(pickerData){
    return pickerData.map((item, index) => {
      return (
        <View style={styles.pickerWheel} key={index}>
          <Picker
            selectedValue={this.state.selectedValue[index]}
            onValueChange={value => {
              this.pickedValue.splice(index, 1, value);
              //do not set state to another object!! why?
              // this.setState({
              //  selectedValue: this.pickedValue
              // });
              this.setState({
                selectedValue: JSON.parse(JSON.stringify(this.pickedValue))
              });
              this.state.onValueChange(JSON.parse(JSON.stringify(this.pickedValue)), index);
            }} >
            {item.map((value, index) => (
              <PickerItem
                key={index}
                value={value}
                label={value.toString()}
              />)
            )}
          </Picker>
        </View>
      );
    });
  }

  _getCascadeData(pickerData, pickedValue, firstPickedData, secondPickedData, onInit){
    let secondWheelData;
    let secondPickedDataIndex;
    let thirdWheelData;
    let thirdPickedDataIndex;
    //only support two and three stage
    for(let key in pickerData){
      //two stage
      if(pickerData[key].constructor === Array){
        secondWheelData = pickerData[firstPickedData];
        if(onInit){
          secondWheelData.forEach(function(v, k){
            if(v === pickedValue[1]){
              secondPickedDataIndex = k;
            }
          }.bind(this));
        }
        else{
          secondPickedDataIndex = 0;
        }
        break;
      }
      //three stage
      else{
        secondWheelData = Object.keys(pickerData[firstPickedData]);
        if(onInit){
          secondWheelData.forEach(function(v, k){
            if(v === pickedValue[1]){
              secondPickedDataIndex = k;
            }
          }.bind(this));
        }
        else{
          secondPickedDataIndex = 0;
        }
        thirdWheelData = pickerData[firstPickedData][secondPickedData];
        if(onInit){
          thirdWheelData.forEach(function(v, k){
            if(v === pickedValue[2]){
              thirdPickedDataIndex = k;
            }
          })
        }
        else{
          thirdPickedDataIndex = 0;
        }
        break;
      }
    }

    return {
      secondWheelData,
      secondPickedDataIndex,
      thirdWheelData,
      thirdPickedDataIndex
    }
  }

  _renderCascadeWheel(pickerData){
    let thirdWheel = this.state.thirdWheelData && (
      <View style={styles.pickerWheel}>
        <Picker
          ref={'thirdWheel'}
          selectedValue={this.state.thirdPickedDataIndex}
          onValueChange={(index) => {
            this.pickedValue.splice(2, 1, this.state.thirdWheelData[index]);
            this.setState({
              thirdPickedDataIndex: index,
              selectedValue: 'wheel3'+index
            });
            this.state.onValueChange(JSON.parse(JSON.stringify(this.pickedValue)), 2);
          }} >
          {this.state.thirdWheelData.map((value, index) => (
            <PickerItem
              key={index}
              value={index}
              label={value.toString()}
            />)
          )}
        </Picker>
      </View>
    );

    return (
      <View style={[styles.pickerWrap, {width: this.state.style.width || width}]}>
        <View style={styles.pickerWheel}>
          <Picker
            ref={'firstWheel'}
            selectedValue={this.state.firstPickedData}
            onValueChange={value => {
              let secondWheelData = Object.keys(pickerData[value]);
              let cascadeData = this._getCascadeData(pickerData, this.pickedValue, value, secondWheelData[0]);
              //when onPicked, this.pickedValue will pass to the parent
              //when firstWheel changed, second and third will also change
              if(cascadeData.thirdWheelData){
                this.pickedValue.splice(0, 3, value, cascadeData.secondWheelData[0], cascadeData.thirdWheelData[0]);
              }
              else{
                this.pickedValue.splice(0, 2, value, cascadeData.secondWheelData[0]);
              }

              this.setState({
                selectedValue: 'wheel1'+value,
                firstPickedData: value,
                secondWheelData: cascadeData.secondWheelData,
                secondPickedDataIndex: 0,
                thirdWheelData: cascadeData.thirdWheelData,
                thirdPickedDataIndex: 0
              });
              this.state.onValueChange(JSON.parse(JSON.stringify(this.pickedValue)), 0);
              this.refs.secondWheel && this.refs.secondWheel.moveTo && this.refs.secondWheel.moveTo(0);
              this.refs.thirdWheel && this.refs.thirdWheel.moveTo && this.refs.thirdWheel.moveTo(0);
            }} >
            {this.state.firstWheelData.map((value, index) => (
              <PickerItem
                key={index}
                value={value}
                label={value.toString()}
              />)
            )}
          </Picker>
        </View>
        <View style={styles.pickerWheel}>
          <Picker
            ref={'secondWheel'}
            selectedValue={this.state.secondPickedDataIndex}
            onValueChange={(index) => {
              let thirdWheelData = pickerData[this.state.firstPickedData][this.state.secondWheelData[index]];
              if(thirdWheelData){
                this.pickedValue.splice(1, 2, this.state.secondWheelData[index], thirdWheelData[0]);
              }
              else{
                this.pickedValue.splice(1, 1, this.state.secondWheelData[index]);
              }

              this.setState({
                secondPickedDataIndex: index,
                thirdWheelData,
                thirdPickedDataIndex: 0,
                selectedValue: 'wheel2'+index
              });
              this.state.onValueChange(JSON.parse(JSON.stringify(this.pickedValue)), 1);
              this.refs.thirdWheel && this.refs.thirdWheel.moveTo && this.refs.thirdWheel.moveTo(0);
            }} >
            {this.state.secondWheelData.map((value, index) => (
              <PickerItem
                key={index}
                value={index}
                label={value.toString()}
              />)
            )}
          </Picker>
        </View>
        {thirdWheel}
      </View>
    );
  }

  _renderWheel(pickerData){
    let wheel = null;
    if(this.pickerStyle === 'parallel'){
      wheel = this._renderParallelWheel(pickerData);
    }
    else if(this.pickerStyle === 'cascade'){
      wheel = this._renderCascadeWheel(pickerData);
    }
    return wheel;
  }

  render(){

    let mask = this.state.showMask ? (
      <View style={styles.mask} >
        <Text style={{width: width, height: height}} onPress={this._pickerCancel.bind(this)}></Text>
      </View>
    ) : null;

    return (
      <Animated.View style={[styles.picker, {
        elevation: this.state.pickerElevation,
        width: longSide,
        height: this.state.showMask ? height : this.state.style.height,
        bottom: this.state.slideAnim
      }]}>
        {mask}
        <View style={[styles.pickerBox, this.state.style]}>
          <View style={[styles.pickerToolbar, this.state.pickerToolBarStyle, {width: this.state.style.width || width}]}>
            <View style={styles.pickerCancelBtn}>
              <Text style={[styles.pickerFinishBtnText, this.state.pickerBtnStyle]}
                onPress={this._pickerCancel.bind(this)}>{this.state.pickerCancelBtnText}</Text>
            </View>
            <Text style={[styles.pickerTitle, this.state.pickerTitleStyle]} numberOfLines={1}>
              {this.state.pickerTitle}
            </Text>
            <View style={styles.pickerFinishBtn}>
              <Text style={[styles.pickerFinishBtnText, this.state.pickerBtnStyle]}
                onPress={this._pickerFinish.bind(this)}>{this.state.pickerBtnText}</Text>
            </View>
          </View>
          <View style={[styles.pickerWrap, {width: this.state.style.width || width}]}>
            {this._renderWheel(this.state.pickerData)}
          </View>
        </View>
      </Animated.View>
    );
  }
};

let styles = StyleSheet.create({
  picker: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    backgroundColor: 'transparent',
  },
  pickerBox: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    backgroundColor: '#bdc0c7'
  },
  mask: {
    position: 'absolute',
    top: 0,
    backgroundColor: 'transparent',
    height: height,
    width: width
  },
  pickerWrap: {
    flexDirection: 'row'
  },
  pickerWheel: {
    flex: 1
  },
  pickerToolbar: {
    height: 44,
    backgroundColor: '#e6e6e6',
    flexDirection: 'row',
    borderTopWidth: 1,
    borderBottomWidth: 1,
    borderColor: '#c3c3c3',
    alignItems: 'center'
  },
  pickerBtnView: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'center'
  },
  pickerMoveBtn: {
    color: '#149be0',
    fontSize: 16,
    marginLeft: 20
  },
  pickerCancelBtn: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'center',
    marginLeft: 20
  },
  pickerTitle: {
    flex: 4,
    color: 'black',
    textAlign: 'center'
  },
  pickerFinishBtn: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'flex-end',
    alignItems: 'center',
    marginRight: 20
  },
  pickerFinishBtnText: {
    fontSize: 16,
    color: '#149be0'
  }
});
